package sse

import (
	"bufio"
	"bytes"
	"encoding/json"
	"fmt"
	"gitee.com/jn-qq/go-tools/data"
	"github.com/google/uuid"
	"github.com/mitchellh/mapstructure"
	"maps"
	"net/http"
	"net/url"
	"slices"
	"strings"
	"vector/tools"
)

// responseSseChat 开发环境sse-chat 接口返回结构
type responseSseChat struct {
	Code                 string         `json:"code"`
	CodeDesc             string         `json:"codedesc"`
	Intent               string         `json:"intent"`
	Status               string         `json:"status"`
	Type                 int            `json:"type"`
	CvsMetricsInfoParams map[string]any `json:"cvsMetricsInfoParams"`
	Data                 struct {
		RespMsg *struct {
			Carddatalist   []any `json:"carddatalist"`
			Barcontentlist []Bar `json:"barcontentlist"`
			DigitalPerson  struct {
				Actions []struct {
					Message string `json:"message"`
					Data    struct {
						Domain       string `json:"domain"`
						HtmlFlag     string `json:"htmlFlag"`
						ReplyGroupId string `json:"replyGroupId"`
						VsmlUri      string `json:"vsmlUri"`
					} `json:"data"`
				} `json:"actions"`
				Message string `json:"message"`
			} `json:"digitalPerson"`
			ThoughtData *struct {
				Content string `json:"content"`
			} `json:"thoughtData"`
			ActionData *struct {
				Content *struct {
					Tip string `json:"tip"`
				} `json:"content"`
			} `json:"actionData"`
		} `json:"respMsg,omitempty"`
	} `json:"data"`
}

// LingXiSseChat sseChat对话接口
type LingXiSseChat struct {
	content      string
	provinceName string
	resultData   map[string]any
	child        []*LingXiDialogueResult
}

func (l *LingXiSseChat) Reset() {
	l.content = ""
	l.provinceName = ""
	clear(l.resultData)
	l.child = nil
}

func (l *LingXiSseChat) NewTaskData(row map[string]any) error {
	l.resultData = maps.Clone(row)
	fliedValues, err := tools.FindStringFromMapAny(l.resultData, "问题", "省份")
	if err != nil {
		return err
	}
	l.content, l.provinceName = fliedValues[0], fliedValues[1]

	return nil
}

func (l *LingXiSseChat) Do() {
	provinceCode, phoneNumber, authCode, _ := tools.Config.Account.GetAccount(l.provinceName)

	// 构建请求参数query
	query := url.Values{}
	for key, value := range tools.Config.SseChat.Params {
		if key == "authCode" && value == "" {
			value = authCode
		}
		query.Set(key, value)
	}

	// 构建请求负载body
	payload := tools.Config.SseChat.GetBody()
	// 设置省份code
	payload["provinceCode"] = provinceCode
	// 设置sessionId
	if payload["sessionId"] == nil || payload["sessionId"] == "" {
		payload["sessionId"] = uuid.New().String()
	}
	// 根据省份设置手机号
	if payload["phoneNumber"] == "" || payload["phoneNumber"] == nil {
		payload["phoneNumber"] = phoneNumber
	}

	var hasErr bool
	var spaceLine int

	for i, question := range strings.Split(l.content, "\n") {
		// 去除空行
		question = strings.TrimSpace(question)
		if question == "" {
			spaceLine++
			continue
		}
		l.child = append(l.child, &LingXiDialogueResult{Question: question})
		if hasErr {
			l.child[i-spaceLine].ErrMessage = "上轮请求过程出现异常，后续跳过"
			continue
		}
		result := l.child[i-spaceLine]

		// 设置问题
		payload["question"] = question
		// 设置traceId
		query.Set("traceId", uuid.New().String())

		// 设置traceId、sessionId
		result.TraceId = query.Get("traceId")
		result.SessionId = payload["sessionId"].(string)

		// 构建请求体
		body, err := json.Marshal(payload)
		if err != nil {
			result.ErrMessage = err.Error()
			hasErr = true
			continue
		}
		if !tools.Config.IsSimplePrint {
			fmt.Println("请求参数：", string(body))
		}

		// 构建请求
		request, err := http.NewRequest(
			"POST",
			tools.Config.SseChat.Address+"?"+query.Encode(),
			bytes.NewBuffer(body),
		)
		if err != nil {
			result.ErrMessage = err.Error()
			hasErr = true
			continue
		}
		request.Header.Set("Content-Type", "application/json")

		// 发送请求
		resp, err := http.DefaultClient.Do(request)
		if err != nil {
			result.ErrMessage = err.Error()
			hasErr = true
			continue
		}
		if resp.StatusCode != http.StatusOK {
			hasErr = true
			result.ErrMessage = "请求失败,状态码：" + resp.Status
			continue
		}

		// 流式读取处理
		reader := bufio.NewReader(resp.Body)
		for {
			line, flg := readerFromSse(reader, '\n')
			if flg == sseBreak {
				break
			} else if flg == sseContinue || line == "" {
				continue
			}

			// 解析 JSON 数据
			res := new(responseSseChat)
			if err = json.Unmarshal([]byte(line), res); err != nil {
				result.ErrMessage = err.Error()
				hasErr = true
				break
			}
			if res.Code != "0000000" {
				result.ErrMessage = res.CodeDesc
				hasErr = true
				break
			} else if res.Data.RespMsg == nil {
				continue
			}

			// 收集卡片
			for _, _card := range res.Data.RespMsg.Carddatalist {
				var card Card
				_ = mapstructure.Decode(_card, &card)
				switch card.Cardnumber {
				case "333":
					if card.Data.Msg != "" && res.Data.RespMsg.DigitalPerson.Message == "" {
						result.Message += card.Data.Msg
					} else {
						continue
					}
				case "8060":
					// 添加思考过程
					result.ThinkList = append(
						result.ThinkList,
						fmt.Sprintf("%s(%s)",
							card.Data.Msg,
							data.TernaryExpression(card.Data.Success, "true", "false"),
						),
					)
				case "-1000", "9999":
					continue
				default:
					if !slices.Contains(result.UniqueId, card.CardId()) {
						result.CardList = append(result.CardList, card)
						result.UniqueId = append(result.UniqueId, card.CardId())
					}
				}

			}
			// 收集气泡
			for _, bar := range res.Data.RespMsg.Barcontentlist {
				if !slices.Contains(result.UniqueId, bar.BarId()) {
					result.Barcontentlist = append(result.Barcontentlist, bar)
					result.UniqueId = append(result.UniqueId, bar.BarId())
				}
			}

			// 新版 思考过程
			if res.Data.RespMsg.ThoughtData != nil {
				result.ThinkList = append(result.ThinkList, res.Data.RespMsg.ThoughtData.Content+"(ds)")
			}
			if res.Data.RespMsg.ActionData != nil {
				result.ThinkList = append(result.ThinkList, res.Data.RespMsg.ActionData.Content.Tip+"(action)")
			}

			// 拼接对话
			result.Message += res.Data.RespMsg.DigitalPerson.Message
			// 意图
			result.Intent = res.Intent
			// 状态
			result.Status = res.Status
			if res.Status == "2" {
				if slots, ok := res.CvsMetricsInfoParams["slots"]; ok {
					if slotMap, ok := slots.(map[string]any); ok {
						result.Slot = slotMap
					}
				}
				break
			}

		}

		resp.Body.Close()
	}

}

func (l *LingXiSseChat) Result() map[string]any {
	var resList []map[string]any
	for _, child := range l.child {
		resList = append(resList, child.ToMap())
	}
	l.resultData["child"] = resList
	return maps.Clone(l.resultData)
}
